package com.dbg.utils;

import com.dbg.entity.ResultEntity;
import com.dbg.entity.ResultSet;
import com.dbg.entity.TestSet;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.draw.SolidLine;
import com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.AreaBreak;
import com.itextpdf.layout.element.LineSeparator;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.properties.HorizontalAlignment;
import com.itextpdf.layout.properties.TextAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;

public class PDFUtils {


    // 保存路径、标题、版本
    private static String SAVE_PATH = "";
    private static String TITLE = "";
    private static String VERSION = "";

    // 私有工厂类用于构建pdf
    private static class Factory {

        // 写入pdf
        public static Document createWriterDocument(String path) throws FileNotFoundException {
            PdfWriter writer = new PdfWriter(path);
            PdfDocument pdf = new PdfDocument(writer);
            pdf.setDefaultPageSize(PageSize.A4);
            Document document = new Document(pdf)
                    .setFontSize(10f);
            document.setLeftMargin(12f);
            document.setRightMargin(12f);
            return document;
        }
        // 读取pdf
        public static Document createReaderDocument(String path) throws IOException {
            PdfReader reader = new PdfReader(path);
            PdfDocument pdf = new PdfDocument(reader);
            return new Document(pdf);
        }
        // 代码内容字体
        public static PdfFont createCodeFont(PdfDocument pdf) throws IOException {
            return PdfFontFactory
                    .createFont("font/SimSun.ttf", "Identity-H", pdf);
        }
        // 封面字体
        public static PdfFont createFirstPageFont(PdfDocument pdf) throws IOException {
            return PdfFontFactory
                    .createFont("font/simhei.ttf", "Identity-H", pdf);
        }
        // 封面段落
        public static Paragraph createFirstPageParagraph(String content, PdfFont font, float lineHeight) {
            if (lineHeight != 0f) {
                return new Paragraph(content)
                        .setBold()
                        .setFont(font)
                        .setFontSize(36)
                        .setTextAlignment(TextAlignment.CENTER);
            }
            return new Paragraph(content)
                    .setFontSize(36);
        }
        public static Paragraph createParagraph(String content, PdfFont font, float codeLineHeight) {
            return new Paragraph(content)
                    .setFont(font)
                    .setMultipliedLeading(codeLineHeight);
        }
    }

    public static void initEnv(String savePath, String title, String version) {
        // 临时变量
        SAVE_PATH = savePath;
        TITLE = title;
        VERSION = version;
    }

    // 扫描文件列表，将文件列表中的文件内容代码读取至临时word，构建为临时pdf，临时pdf再判断是否大于3000行，构建为标准格式，并获得代码总行数
    public static ResultEntity codeToPdf(List<String> codeFileList, String savePath, String title, String version) throws IOException {
        initEnv(savePath, title, version);  // 初始化环境

        // 临时文件路径汇总
        String tempPDF = SAVE_PATH + "\\" + TITLE + VERSION + "temp.pdf";
        String tempDOCX = SAVE_PATH + "\\" + TITLE + VERSION + "temp.docx";

        // 构建临时DOCX
        XWPFDocument docx = new XWPFDocument();
        try {
            FileOutputStream out = new FileOutputStream(tempDOCX);
            DocxUtils.addParagraph(docx, codeFileList, JSONUtils.languagesList, JSONUtils.patternsList);
            docx.write(out);
        } catch (IOException e) {
            System.err.println("写入DOCX时出错: " + e.getMessage());
            return ResultSet
                    .ERROR
                    .setMessage("msg", "写入DOCX时出错: " + e.getMessage());
        }

        // 临时pdf
        Document pdfDocument = PDFUtils.Factory.createWriterDocument(tempPDF);
        // 将临时docx写入临时pdf
        List<String> lines = FileUtils.scanDocxToList(tempDOCX);
        for (String line : lines) {
            addParagraphInLine(pdfDocument, line);
        }

        // 关闭文件，先关闭写入文件，才能只读打开文件
        pdfDocument.close();
        docx.close();

        ResultEntity result = FileUtils.deleteFile(tempDOCX);
        if (result.isERROR()) {
            return ResultSet
                    .ERROR
                    .setMessage("msg", "删除临时docx失败");
        }

        // 将代码添加页码、页眉，超3000行就减少至3000行
        return formatToStandard(tempPDF);
    }

    // 格式化为标准文档内容
    public static ResultEntity formatToStandard(String sourcePdfPath) throws IOException {
        // 代码行高
        float codeLineHeight = 0.53f;
        // 页眉行高
        float headerLineHeight = 0.75f;
        // pdf源文件
        PdfDocument sourcePDF = PDFUtils.Factory.createReaderDocument(sourcePdfPath).getPdfDocument();
        // pdf目标文件
        Document targetPDF = PDFUtils.Factory.createWriterDocument(SAVE_PATH + "\\" + TITLE + VERSION + "源程序.pdf");
        // 目标PDF字体
        PdfFont targetFont = PDFUtils.Factory.createCodeFont(targetPDF.getPdfDocument());
        // 添加封面
        addFirstPage(targetPDF);

        // 所有代码
        ArrayList<String> lineList = new ArrayList<>();

        // 提取所有行
        for (int i = 1; i <= sourcePDF.getNumberOfPages(); i++) {
            // 提取页面内容
            String pageContent = PdfTextExtractor.getTextFromPage(sourcePDF.getPage(i));
            String[] lines = pageContent.split("\n");
            lineList.addAll(Arrays.asList(lines));
        }

        // 代码行数
        int line = (lineList.size() + 50) - (lineList.size() % 50);

        // 小于3000行的处理方式
        if (lineList.size() <= 3000) {
            line = lineList.size();
            for (int i = 1; i < lineList.size(); i++) {
                if (i % 50 == 1) {
                    addHeaderAndPageCode(targetPDF, targetFont, headerLineHeight, (i / 50) + 1);
                }
                targetPDF.add(PDFUtils.Factory.createParagraph(lineList.get(i - 1), targetFont, codeLineHeight));
            }
        } else {
            // 偏移量页码在首行
            int offset = 0;
            boolean offsetOpen = false;
            for (int i = 1; i <= lineList.size(); i++) {
                if (i <= 1500) {
                    if (i % 50 == 1) {
                        addHeaderAndPageCode(targetPDF, targetFont, headerLineHeight, (i / 50) + 1);
                    }
                    targetPDF.add(PDFUtils.Factory.createParagraph(lineList.get(i - 1), targetFont, codeLineHeight));
                } else if (lineList.size() - 1499 <= i) {
                    if (!offsetOpen) {
                        offset = i % 50;
                        offsetOpen = true;
                    }
                    if (i % 50 == offset) {
                        addHeaderAndPageCode(targetPDF, targetFont, headerLineHeight, (i / 50) + 2);
                    }
                    targetPDF.add(PDFUtils.Factory.createParagraph(lineList.get(i - 1), targetFont, codeLineHeight));
                }
            }
        }

        // 关闭所有资源
        targetPDF.close();
        sourcePDF.close();

        ResultEntity result = FileUtils.deleteFile(sourcePdfPath);
        if (result.isERROR()) {
            return ResultSet
                    .ERROR
                    .setMessage("msg", "删除临时pdf文件失败");
        }

        return ResultSet
                .SUCCESS
                .setMessage("line", line);
    }

    // 添加封面
    public static void addFirstPage(Document pdf) throws IOException {
        // 封面字体
        PdfFont firstPageFont = PDFUtils.Factory
                .createFirstPageFont(pdf.getPdfDocument());
        // 封面线条
        LineSeparator LINESEPARATOR = new LineSeparator(new SolidLine(1f))
                .setHorizontalAlignment(HorizontalAlignment.CENTER);
        pdf.add(LINESEPARATOR);
        // 先来几个空行
        Paragraph noneLine = PDFUtils.Factory.createFirstPageParagraph("  ", firstPageFont, 0f);
        for (int i = 1; i < 22; i++) {
            pdf.add(noneLine);
        }
        Paragraph firstPageParagraph = PDFUtils.Factory.createFirstPageParagraph(TITLE + " " + VERSION, firstPageFont, 0.75f);
        Paragraph firstPageParagraph1 = PDFUtils.Factory.createFirstPageParagraph("源程序", firstPageFont, 0.75f);
        pdf.add(firstPageParagraph);
        pdf.add(firstPageParagraph1);
        pdf.add(new AreaBreak());
    }

    // 计算标题行数
    public static int calculationLineOfTitle(String title) {
        char[] charArray = title.toCharArray();
        int lineNum = 0;
        int buffNum = 0;
        for (char c : charArray) {
            int num = CodeUtils.judgeChinese(c) ? 2 : 1;
            if (buffNum + num <= 32) {
                buffNum += num;
            } else {
                lineNum ++;
                buffNum = num;
            }
        }
        if (buffNum != 0) {
            lineNum ++;
        }
        return lineNum;
    }

    // 添加页眉、页码
    public static void addHeaderAndPageCode(Document pdf, PdfFont font, float lineHeight, int pageCode) {
        Paragraph pageCodeParagraph = PDFUtils.Factory
                .createParagraph(String.valueOf(pageCode), font, lineHeight)
                .setTextAlignment(TextAlignment.RIGHT)
                .setBold();
        Paragraph headerParagraph = PDFUtils.Factory.createParagraph(TITLE + " " + VERSION, font, lineHeight)
                .setTextAlignment(TextAlignment.CENTER)
                .setBold();
        LineSeparator LINESEPARATOR = new LineSeparator(new SolidLine(1f))
                .setHorizontalAlignment(HorizontalAlignment.CENTER);
        pdf.add(pageCodeParagraph);
        pdf.add(headerParagraph);
        pdf.add(LINESEPARATOR);

    }

    // 添加新段落，一段落一行
    public static void addParagraphInLine(Document document, String line) throws IOException {
        // 行高
        float codeLineHeight = 0.60f;

        // 单行限制字数
        int limit = 115;
        char[] lineChar = line.toCharArray();

        // 单行字数临时变量、临时行内内容
        int fontWidthAll = 0;
        String newParagraphContent = "";

        // 字体
        PdfFont font = PDFUtils.Factory
                .createCodeFont(document.getPdfDocument());

        for (int i = 0; i < lineChar.length; i++) {
            int fontWidth = CodeUtils.judgeChinese(lineChar[i]) ? 2 : 1;
            if (fontWidthAll + fontWidth < limit) { // 判断中文字符
                fontWidthAll += fontWidth;
                newParagraphContent += lineChar[i];
            } else {
                document.add(PDFUtils.Factory.createParagraph(newParagraphContent, font, codeLineHeight));
                fontWidthAll = fontWidth;
                newParagraphContent = String.valueOf(lineChar[i]);
            }
        }
        if (fontWidthAll != 0) {
            document.add(PDFUtils.Factory.createParagraph(newParagraphContent, font, codeLineHeight));
        }
    }

    public static void main(String[] args) throws IOException {
        Set<String> strings = TestSet.javaLanguageSet();
        HashMap<String, Integer> sortRule = TestSet.javaSortRule();

//        List<String> strings1 = FileUtils.iterationFile("D:\\java\\v2\\word_code\\src", strings, sortRule);
//        PDFUtils.codeToPdf(strings1, "C:\\Users\\someo\\Desktop\\软著\\33", "word_code", "v1.0");
        List<String> strings1 = FileUtils.iterationFile("C:\\Users\\someo\\Desktop\\bs\\bs\\intelligent_job_system-master", strings, sortRule);
        PDFUtils.codeToPdf(strings1, "C:\\Users\\someo\\Desktop\\软著\\33", "test", "v1.0");
//        List<String> strings1 = FileUtils.iterationFile("C:\\Users\\Administrator\\Desktop\\bs\\20241013234204\\intelligent_job_system-master", strings, sortRule);
//        PDFUtils.codeToPdf(strings1, "C:\\Users\\Administrator\\Desktop\\bs\\20241013234204", "test", "v1.0");

    }



}
